package main

import (
	"errors"
	"fmt"
	"go.manyji.com/lib/encoding/json"
	"io"
	"net/http"
	"os"
	pkgRand "sieve_admin_server/pkg/rand"
	"strings"
	"sync"
)

func userInfoHttpCall(accountId uint64) (string, error) {

	url := "http://192.168.1.138:9608/customer/user/query_list"
	method := "POST"

	payload := strings.NewReader(fmt.Sprintf("currVer=20221116&page_index=1&page_size=3&id=%v", accountId))

	client := &http.Client{}
	req, err := http.NewRequest(method, url, payload)

	if err != nil {
		return "", err
	}
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Cookie", "app51_session=659-iWWZWcxWvFQjH/z/Oizzw0JL9kk0tyu1Yp8oHdpnBwY=")

	res, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()

	body, err := io.ReadAll(res.Body)
	if err != nil {
		return "", err
	}

	fmt.Println("get user info:", string(body))
	return string(body), nil
}

func rechargeHttpCall(data map[string]interface{}) (string, error) {
	url := "http://192.168.1.138:9608/customer/recharge/add_item"
	method := "POST"

	//payload := strings.NewReader("currVer=20221116&account_id=10000&recharge_points=100&bonus_points=100&refund_points=50&type=1")
	payload := strings.NewReader(
		fmt.Sprintf(
			"currVer=20221116&account_id=%v&recharge_points=%v&bonus_points=%v&refund_points=%v&type=%v",
			data["account_id"],
			data["recharge_points"],
			data["bonus_points"],
			data["refund_points"],
			data["type"]))

	client := &http.Client{}
	req, err := http.NewRequest(method, url, payload)

	if err != nil {
		return "", err
	}
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Cookie", "app51_session=659-iWWZWcxWvFQjH/z/Oizzw0JL9kk0tyu1Yp8oHdpnBwY=")

	res, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()

	body, err := io.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	if string(body) != "" {
		return "", errors.New(string(body))
	}

	return string(body), nil
}

func recharge() {

	var (
		//userList = []uint64{661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680}
		userList = []uint64{661}

		// 用户随机充值次数
		items = make(map[uint64][]map[string]interface{}, 0)

		// 用户充值后的总金额
		failedTotalRecharge = make(map[uint64]map[string]float64, 0)
		lock                = sync.Mutex{}
		totalRecharge       = make(map[uint64]map[string]float64, 0)
		totalRechargeBefore = make(map[uint64]map[string]float64, 0)
	)

	for i := 0; i < len(userList); i++ {
		uid := userList[i]
		if resp, err := userInfoHttpCall(uid); err != nil {
			continue
		} else {
			data := make(map[string]interface{})
			_ = json.Unmarshal([]byte(resp), &data)

			kv := data["list"].([]interface{})[0].(map[string]interface{})

			r := map[string]float64{
				"recharge_points": kv["recharge_points"].(float64),
				"bonus_points":    kv["bonus_points"].(float64),
			}
			totalRechargeBefore[uid] = r
		}
	}

	for i := 0; i < len(userList); i++ {

		rpCount := pkgRand.N(1, 10)
		sum := make(map[string]float64)
		item := make([]map[string]interface{}, 0)
		for j := 0; j < rpCount; j++ {
			refundP := pkgRand.N(1, 50)
			item = append(item, map[string]interface{}{
				"account_id":    userList[i],
				"refund_points": float64(refundP),
				"type":          2,
			})
			sum["refund_points"] += float64(refundP)
		}

		if _, ok := totalRecharge[userList[i]]; !ok {
			totalRecharge[userList[i]] = make(map[string]float64, 0)
		}
		totalRecharge[userList[i]] = sum

		if _, ok := items[userList[i]]; !ok {
			items[userList[i]] = make([]map[string]interface{}, 0)
		}

		items[userList[i]] = item
	}

	var (
		gorMap = map[uint64]int{}
	)
	wp := sync.WaitGroup{}
	for k := range items {
		gorCount := pkgRand.N(2, 3)

		gorMap[k] = gorCount
	}
	var gorTotal int
	for _, v := range gorMap {
		gorTotal += v
	}

	wp.Add(gorTotal)

	for k, v := range items {

		gorCount := gorMap[k]
		vCopy := v
		for j := 0; j < gorCount; j++ {
			go func(uid int, index int, datas []map[string]interface{}) {
				fmt.Printf("用户 %v 协程 %v 需要退款次数：%v\n", k, index, len(datas))
				for i, data := range datas {

					if _, err := rechargeHttpCall(data); err != nil {
						if _, ok := failedTotalRecharge[uint64(uid)]; !ok {
							lock.Lock()
							failedTotalRecharge[uint64(uid)] = make(map[string]float64, 0)
							lock.Unlock()
						}
						lock.Lock()
						failedTotalRecharge[uint64(uid)]["refund_points"] += data["refund_points"].(float64)
						lock.Unlock()
						fmt.Printf(fmt.Sprintf("用户 %v 总共 %v 个协程，当前协程ID:%v 第 %v 次退款成功，总共要退款:%v 次，失败积分：%v,用户ID:%v ,充值失败原因：%+v\n",
							uid, gorCount, index, i+1, len(datas), data["refund_points"], k, err))
					} else {
						fmt.Printf("用户 %v 总共 %v 个协程，当前协程 %v 第 %v 次退款成功，总共要退款:%v 次 本次扣款（充值积分：%v）\n",
							uid, gorCount, index, i+1, len(datas), data["refund_points"])
					}
				}
				wp.Done()
			}(int(k), j, vCopy)
		}

		fmt.Printf("用户%v有%v个协程并发扣款\n", k, gorCount)
	}

	fmt.Printf("总共%v个用户，%v个协程\n", len(items), gorTotal)
	wp.Wait()

	for k, v := range totalRecharge {
		uid := k
		if resp, err := userInfoHttpCall(uid); err != nil {
			fmt.Printf("获取用户信息：%v 失败\n", uid)
		} else {
			data := make(map[string]interface{})
			_ = json.Unmarshal([]byte(resp), &data)

			totalRechargeAfter := data["list"].([]interface{})[0].(map[string]interface{})

			if totalRechargeAfter["recharge_points"].(float64)+v["refund_points"]*float64(gorMap[uid])+failedTotalRecharge[uid]["refund_points"] == totalRechargeBefore[uid]["recharge_points"] {
				fmt.Printf("用户 %v 退款无误,应扣除积分：%v，扣除前积分：%v，扣除后积分：%v\n",
					uid,
					v["refund_points"]*float64(gorMap[uid]),
					totalRechargeBefore[uid]["recharge_points"],
					totalRechargeAfter["recharge_points"].(float64),
				)
			} else {
				fmt.Printf("用户 %v 退款有误,应扣除积分：%v，失败积分：%v，扣除前积分：%v，扣除后积分：%v 实际扣款：%v 少扣了：%v\n",
					uid,
					v["refund_points"]*float64(gorMap[uid]),
					failedTotalRecharge[uid]["refund_points"],
					totalRechargeBefore[uid]["recharge_points"],
					totalRechargeAfter["recharge_points"].(float64),
					totalRechargeBefore[uid]["recharge_points"]-totalRechargeAfter["recharge_points"].(float64),
					v["refund_points"]*float64(gorMap[uid])-(totalRechargeBefore[uid]["recharge_points"]-totalRechargeAfter["recharge_points"].(float64)),
				)
				os.Exit(-1)
			}
		}
	}

	return
}

func main() {

	for {
		recharge()
		//break
		//time.Sleep(time.Second * 10)
	}
}
